package com.sunday.authorization.security.access;

import com.sunday.authorization.security.authentication.CustomAuthenticationException;
import com.sunday.common.core.enums.ErrorCodeEnum;
import com.sunday.common.core.remoting.base.response.Response;
import com.sunday.common.core.remoting.rest.response.RestResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.util.ReflectionUtils;

import java.io.IOException;
import java.lang.reflect.Method;

/**
 * TODO
 *
 * @author sunday
 * @see AbstractAuthenticationProcessingFilter#setAuthenticationFailureHandler(AuthenticationFailureHandler)
 * @see SimpleUrlAuthenticationFailureHandler#onAuthenticationFailure(HttpServletRequest, HttpServletResponse, AuthenticationException)
 * @since 2024/9/14
 */
@Slf4j
public class JsonAuthenticationFailureHandler implements AuthenticationFailureHandler {

    private static final Method method;

    static {
        method = ReflectionUtils.findMethod(Response.class, "resultReturn", String.class, String.class);
        method.setAccessible(true);
    }

    /**
     * 如果帐户被禁用并且AuthenticationManager可以测试此状态，则必须抛出DisabledException。
     * 如果帐户被锁定并且AuthenticationManager可以测试帐户锁定，则必须抛出LockedException。
     * 如果提供了不正确的凭据，必须抛出BadCredentialsException。虽然上述异常是可选的，但AuthenticationManager必须始终测试凭据
     *
     * @see AuthenticationManager
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException exception) throws IOException, ServletException {

        log.info("登陆失败 {}", exception.toString());

        Response response = Response.error(ErrorCodeEnum.A0_200);

//        if (exception instanceof BadCredentialsException) {
//            writeErrorMessage(httpServletResponse, Response.error(ErrorCodeEnum.A0_210, "用户账户或密码错误"));
//        }
////        else if (exception instanceof LockedException) {
////            // A0_322(ErrorClassifyEnum.A + "0322","账号被冻结"),
////            return writeErrorMessage(response, ErrorCodeEnum.A0_322);
////        }
//        else
        if (exception instanceof CustomAuthenticationException customEx) {
            response = Response.class.cast(ReflectionUtils.invokeMethod(method, response, customEx.getCode(), customEx.getMessage()));
            writeErrorMessage(httpServletResponse, response);
        } else {
            // A0_200(ErrorClassifyEnum.A, STR."\{ErrorClassifyEnum.A}0200", "用户登录异常")
            writeErrorMessage(httpServletResponse, response);
        }


    }

    private void writeErrorMessage(HttpServletResponse httpServletResponse, Response response) throws IOException {
        RestResponse<String> restResponse = RestResponse.resultReturn(response, RestResponse.ShowTypeEnum.SILENT);
        writeErrorMessage(httpServletResponse, restResponse);
    }

    private void writeErrorMessage(HttpServletResponse httpServletResponse, RestResponse<String> restResponse) throws IOException {
        /**
         * response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
         * response.sendError 会已text/html页面的形式返回
         */
        httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        httpServletResponse.getWriter().write(restResponse.toJson());
        httpServletResponse.getWriter().flush(); // 明确刷新输出流，立即发送响应
    }

}
